package cn.tedu.charging.user.service;

import cn.tedu.charging.common.constant.AppInfoConst;
import cn.tedu.charging.common.enums.VehicleUserBindEnum;
import cn.tedu.charging.common.pojo.param.ChargeParam;
import cn.tedu.charging.common.pojo.param.VehicleBindParam;
import cn.tedu.charging.common.pojo.po.ChargingUserInfoPO;
import cn.tedu.charging.common.pojo.po.ChargingUserVehicleBindPO;
import cn.tedu.charging.common.pojo.po.ChargingVehiclePO;
import cn.tedu.charging.common.pojo.vo.BalanceVO;
import cn.tedu.charging.common.pojo.vo.VehicleVO;
import cn.tedu.charging.user.repository.UserRepository;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class UserServiceImpl implements UserService{
//    这样避免直接去操作数据库，避免代码冗余，提高了代码的维护
    @Autowired
    private UserRepository userRepository;

    @Override
    public Integer wxLogin(String nickname, String code) {
//        1、使用微信授权码，获取授权服务器的openId
        String openId = getOpenId(code);
//        2、判断是否正确获取
        if (openId==null || openId.length()==0){
            log.debug("获取openId失败");
            throw new RuntimeException("获取openId失败");
        }
//        3、查询本地车主是否有绑定这个openId的数据
           ChargingUserInfoPO po = userRepository.getUserByOpenId(openId);
//        4、判断本地车主是否绑定这个openId的数据
        if (po==null){
//        5、组织一个新的userInfoPo 补充必要属性写入的数据库
//        将新生成的po返回id
            po = new ChargingUserInfoPO();
//        openId绑定
            po.setWxOpenId(openId);
//        nickname
            po.setNickName(nickname);
//        createTime
            po.setCreateTime(new Date());
            po.setUpdateTime(new Date());
            userRepository.save(po);
        }
        return po.getId();
    }

    @Override
    public BalanceVO getBalance(Integer userId) {
//        余额数据 在数据库表 字段balance
        ChargingUserInfoPO po  = userRepository.getBalance(userId);
        if (po==null){
            log.debug("获取余额失败");
            throw new RuntimeException("获取余额失败");
        }
        BalanceVO balanceVO = new BalanceVO();
        balanceVO.setBalance(po.getBalance());
        return balanceVO;
    }

    @Override
    public void charge(ChargeParam chargeParam) {
        userRepository.updateByUserId(chargeParam);
    }

    @Override
    public VehicleVO getVehicle(Integer userId) {
//        1、使用userid 以及状态state=1 查询用户绑定车辆
//        对于状态 状态码 字典类型，变动不大的数据 可以放到枚举和常量
//        星期  月 等地名适合做枚举， 但是数据一旦大了，就应该放到字典项
        List<ChargingUserVehicleBindPO>  list = userRepository.getBindedVehicle(userId, VehicleUserBindEnum.BINDED.getState());
//        2、判断是否有数据， 判断数据是否合法，pos。size（）>1不合法
//        2.1 空 返回空
        VehicleVO vehicleVO = new VehicleVO();
        if (list==null || list.size()==0){
            log.debug("获取绑定车辆失败");
        } else if (list.size()==1) {
            ChargingVehiclePO vehiclePO= userRepository.getVehicleById(list.get(0).getVehicleId());
            BeanUtils.copyProperties(vehiclePO,vehicleVO);
        }else {
            log.debug("获取绑定车辆失败");
        }
        return vehicleVO;
    }

    @Override
    public void bindVehicle(VehicleBindParam vehicleBindParam) {
//        确定车辆信息可以使用牌子，最好还是使用vehicle_id
//        1、查询该用户是否存在正在使用绑定的车辆
        List<ChargingUserVehicleBindPO> bindedVehicle = userRepository.getBindedVehicle(vehicleBindParam.getUserId(), VehicleUserBindEnum.BINDED.getState());
//        2、判断非空
        if (bindedVehicle!=null && bindedVehicle.size()>0){
            log.debug("用户已经绑定了车辆");
        }
//        3、undo  验证车辆信息是否正确
//        4、使用牌子license查询vehicle中是否存在车辆信息
        ChargingVehiclePO chargingVehiclePO = userRepository.getVehicleByLicense(vehicleBindParam.getLicense());
        if (chargingVehiclePO==null){
            BeanUtils.copyProperties(vehicleBindParam,chargingVehiclePO);
            chargingVehiclePO.setUpdateTime(new Date());
            chargingVehiclePO.setCreateTime(new Date());
            userRepository.insertVehicle(chargingVehiclePO);
        }
//        5、生成绑定 由用户 有车辆 只负责绑定 user_id vehicle_id state=1
//        保证如果用户对车辆解绑 state=0 重新绑定 是相同的user_id vehicle_id state=0
//        先删除 绑定数据 不一定能删除数据 在进行绑定
        userRepository.deleteBindedVehicle(vehicleBindParam.getUserId(),chargingVehiclePO.getId());
        ChargingUserVehicleBindPO chargingUserVehicleBindPO = new ChargingUserVehicleBindPO();
        chargingUserVehicleBindPO.setCreateTime(new Date());
        chargingUserVehicleBindPO.setVehicleId(chargingVehiclePO.getId());
        chargingUserVehicleBindPO.setUserId(vehicleBindParam.getUserId());
        chargingUserVehicleBindPO.setState(VehicleUserBindEnum.BINDED.getState());
        userRepository.bindVehicle(chargingUserVehicleBindPO);
    }

    private String getOpenId(String code) {
//        按照腾讯授权服务器接口的文档 拼接参数 发送请求
        RestTemplate restTemplate = new RestTemplate();
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid={1}&secret={2}&js_code={3}&grant_type=authorization_code";
//        2、解析响应体 直接解析json字符串，封装一个对象接受wxopenIdDTO
//        对于appid secret 后端保存记录的数据 而且几乎不会变动 所以放到常量或者枚举中
        String wxLoginJson = restTemplate.getForObject(url, String.class, AppInfoConst.APP_ID, AppInfoConst.APP_SECRET, code);
//      将json利用fastJson工具解析成jsonObject（key=value).get("openId)
        JSONObject jsonObject = JSON.parseObject(wxLoginJson);
        //openid=123,  session_key=456,errorcode=123...
        String openid = jsonObject.getString("openid");
        return openid;
    }
}
